package org.example.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Objects;

/**
 * Created by zw531 on 2018/1/13.
 * AOP拦截顺序按照@Order中指定的数值来定, 数值越小越靠前.
 */
@Aspect
@Component
@Slf4j
public class AccessLogger {
    private static final ThreadLocal<Long> START_TIME_LOGGER = new ThreadLocal<>();

    /**
     * 定义切面, 匹配某个包下的所有方法
     */
    @Pointcut("execution(public * org.example.web..*.*(..))")
    public void logWebFlow() {
    }

    @Before("logWebFlow()")
    @Order(3)
    public void doBefore() {
        // 记录每个request的开始时间
        START_TIME_LOGGER.set(System.currentTimeMillis());
    }

    @AfterReturning(returning = "ret", pointcut = "logWebFlow()")
    @Order(5)
    public void doAfterReturning(Object ret) {
        // 对返回值要处理的, 可以在这里动手
        log.info("RESPONSE : " + ret);
    }

    @After("logWebFlow()")
    @Order(7)
    public void doAfter(JoinPoint joinPoint) {
        // 获取HTTP请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        // 记录来访IP与响应方法以及耗时
        log.info("URL: " + request.getRequestURL().toString());
        log.info("HTTP METHOD: " + request.getMethod());
        log.info("IP: " + request.getRemoteAddr());
        log.info("CLASS METHOD: " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));
        log.info("SPEED TIME: {}ms", (System.currentTimeMillis() - START_TIME_LOGGER.get()));
        // 清理掉弱引用避免内存泄漏
        START_TIME_LOGGER.remove();
    }
}